home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / mint / filesy~1 / mfs610s.zoo / fsck / fsck.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-05-12  |  30.7 KB  |  1,494 lines

  1. /* Filesystem checker : Contains most of the elements of BSD fsck(8) that
  2.  * make sense under minix filesystems.
  3.  * Copyright 1992,1993,1994 S.N. Henson, all rights reserved.
  4.  * Version 0.0 pre-alpha [i.e. likely to be buggy].
  5.  */
  6.  
  7. /* Patchlevel 9 */
  8.  
  9. #include <sys/types.h>
  10. #include <unistd.h>
  11. #include <alloc.h>
  12. #include <time.h>
  13. #include <stdio.h>
  14. #include <macros.h>        /* For min(x,y) */
  15. #include <string.h>
  16. #include <stdlib.h>
  17. #include <time.h>
  18.  
  19. #include "fs.h"
  20. #include "fsck.h"
  21. #include "global.h"
  22. #include "proto.h"
  23. #include "stproto.h"
  24.  
  25. void do_fsck()
  26. {
  27.     int pass;
  28.     long i;
  29.  
  30.     /* Filesystem dependent check */
  31.  
  32.     i = 2+Super->s_zmap_blks+Super->s_imap_blks
  33.                         +(Super->s_ninodes+IPB-1)/IPB;
  34.  
  35.     if( Super->s_firstdatazn < i ) sfatal("First Data Zone too small");
  36.  
  37.     /* Maybe using new protection ? */
  38.     if( Super->s_firstdatazn > i ) 
  39.     {
  40.         unsigned char *tblock;
  41.         long secsize;
  42.         tblock = malloc(BLOCKSIZE);
  43.         if(!tblock) fatal("No memory for boot sector buffer");
  44.         read_zone(0,tblock);
  45.         secsize = tblock[0xb]+(tblock[0xc]<<8);
  46.         if( ((secsize & 1023 ) == 0))
  47.         {
  48.             secsize/=1024;
  49.             i+= 2 * secsize - 1;
  50.             i/=secsize;
  51.             i*=secsize;
  52.         }
  53.         free(tblock);
  54.     }
  55.  
  56.     if( Super->s_firstdatazn != i ) fprintf(stderr,"Warning: First data" 
  57.         " zone block %d, expected %ld\n",Super->s_firstdatazn,i);
  58.  
  59.     /* Allocate status arrays */
  60.  
  61.     ibitmap=calloc(BLOCKSIZE*(Super->s_zmap_blks*2 + Super->s_imap_blks) +
  62.                     sizeof(inode_stat)*Super->s_ninodes,1);
  63.  
  64.     if(!ibitmap)fatal("No memory for Zone bitmaps");
  65.  
  66.     zbitmap=(unsigned *)( ( (long)ibitmap )+ BLOCKSIZE*Super->s_imap_blks);
  67.     szbitmap=(unsigned *)( ( (long)zbitmap ) + BLOCKSIZE*Super->s_zmap_blks);
  68.     inode_status=(inode_stat *)(szbitmap +(szbitmap-zbitmap));
  69.  
  70.     setbit(0,szbitmap);
  71.  
  72.     /* Flags for root inode */
  73.     inode_status->flag |= I_FOUND;
  74.     inode_status->parent= ROOT_INODE;
  75.  
  76.     /* Read in all bitmaps */
  77.     read_blocks(2,Super->s_imap_blks+Super->s_zmap_blks,ibitmap);
  78.     ioff=2+Super->s_imap_blks+Super->s_zmap_blks;
  79.  
  80.     check_root();
  81.  
  82.     printf("Pass 1 Checking All Inodes\n");
  83.  
  84.     ist=inode_status;
  85.     next_init();
  86.  
  87.     for(cino=ROOT_INODE;cino<=maxino;cino++,ist++)
  88.     {
  89.         next_inode();
  90.         if(badroot && (cino==ROOT_INODE) ) continue;
  91.         ist->links=rip->i_nlinks;
  92.         switch(rip->i_mode & I_TYPE)
  93.         {
  94.             case I_NOT_ALLOC:
  95.             ist->flag|=I_FREE;
  96.             if(rip->i_nlinks)
  97.             {
  98.                 printf("Non zero link count for Free inode %ld\n",cino);
  99.                 if(ask("Alter?","Altered"))
  100.                 {
  101.                     rip->i_nlinks=0;
  102.                     ist->links=0;
  103.                     cdirty=1;
  104.                 }
  105.             }
  106.             break;
  107.  
  108.             case I_CHAR_SPECIAL:
  109.             nchr++;
  110.             break;
  111.  
  112.             case I_BLOCK_SPECIAL:
  113.             nblk++;
  114.             break;
  115.  
  116.             case I_NAMED_PIPE:
  117.             nfifo++;
  118.             break;
  119.  
  120.             case I_REGULAR:
  121.             nreg++;
  122.             traverse_zones(pass1);
  123.             break;
  124.  
  125.             case I_DIRECTORY:
  126.             ndir++;
  127.             if(rip->i_size & (DSIZE*incr-1))
  128.             {
  129.                 inerr("Partial Entry");
  130.                 if(ask("Truncate?","Truncated"))
  131.                 {
  132.                     rip->i_size &= ~(DSIZE*incr-1);
  133.                     cdirty=1;
  134.                     trunc=2;
  135.                 }
  136.             }
  137.             traverse_zones(pass1);
  138.             trunc=0;
  139.             ist->flag|=I_DIR;
  140.             break;
  141.  
  142.             case I_OLDLINK:
  143.             inerr("Old style symbolic link");
  144.             if(ask("Convert?","Converted"))
  145.             {
  146.                 rip->i_mode &= ALL_MODES;
  147.                 rip->i_mode |= I_SYMLINK;
  148.                 cdirty=1;
  149.             }
  150.             /* Fall through */
  151.  
  152.             case I_SYMLINK:
  153.             nsym++;
  154.             traverse_zones(pass1);
  155.             break;
  156.  
  157.             default:
  158.             printf("Unknown Mode 0%o Inode %ld\n",rip->i_mode,cino);
  159.             if(ask("Clear?","Cleared"))
  160.             {
  161.                 *rip=zinode;
  162.                 cdirty=1;
  163.                 ist->links=0;
  164.             }
  165.         }
  166.     }
  167.  
  168.     if(fzlist)
  169.     {
  170.         if(preen) fatal("Duplicate zones found when preening");
  171.         printf("Pass 1a finding duplicate zones\n");
  172.         next_init();
  173.         for(cino=ROOT_INODE;cino<=maxino;cino++)
  174.         {
  175.             next_inode();
  176.             if(badroot && (cino==ROOT_INODE) ) continue; 
  177.             switch(rip->i_mode & I_TYPE)
  178.             {
  179.                 case I_SYMLINK:
  180.                 case I_REGULAR:
  181.                 case I_DIRECTORY:
  182.                 traverse_zones(pass1a);
  183.  
  184.                 default:
  185.                 break;
  186.             }
  187.         }
  188.     }
  189.  
  190.     next_init();
  191.  
  192.     if(badroot) fix_root();
  193.  
  194.     for(pass=0;pass<4;pass++)
  195.     {
  196.         char first=0;
  197.         switch(pass)
  198.         {
  199.             case 0:
  200.             printf("Pass 2 Reading Directories\n");
  201.             break;
  202.             
  203.             case 1:
  204.             printf("Pass 3 Checking Connectivity\n");
  205.             break;
  206.  
  207.             case 2:
  208.             case 3:
  209.             first=0;
  210.             break;
  211.         }
  212.         read_inode_init();
  213.         ist=inode_status;
  214.         for(cino=ROOT_INODE;cino<=maxino;cino++,ist++)
  215.         {
  216.             if(!(ist->flag & I_DIR)) continue;
  217.             if( (pass==2) && !(ist->flag & I_LINK) ) continue;
  218.             if( (pass==3) && ( !(ist->flag & (I_FDD|I_FIXDD)) 
  219.                     || !(ist->flag & I_DD) ) ) continue;
  220.             read_inode();
  221.             switch(pass)
  222.             {
  223.                 case 0:
  224.                 check_dots();
  225.                 break;
  226.  
  227.                 case 1:
  228.                 traverse_dir(pass2);
  229.                 break;
  230.  
  231.                 case 2:
  232.                 if(!first)
  233.                 {
  234.                     printf("Pass 3a Fixing Directories\n");
  235.                     first=1;
  236.                 }
  237.                 traverse_dir(pass2a);
  238.                 break;
  239.  
  240.                 case 3:
  241.                 if(!first)
  242.                 {
  243.                     printf("Pass 3b Fixing Dots\n");
  244.                     first=1;
  245.                 }
  246.                 fix_dots();
  247.                 break;
  248.             }
  249.         }
  250.     }
  251.     ist=inode_status;
  252.  
  253.     if(inolist)
  254.     {
  255.         ilist *p;
  256.         for(p=inolist;p;p=p->next) show_name(p);
  257.     }
  258.  
  259.     for(cino=ROOT_INODE;cino<=maxino;cino++,ist++)
  260.     {
  261.  
  262.         if( !(ist->flag & I_FOUND) && !(ist->flag & I_FREE) )
  263.         {
  264.             inerr("Orphaned Inode");
  265.             if(ask("Reconnect?","Reconnected"))
  266.             {
  267.                 dir_struct tdir[DPB/2];
  268.                 unsigned tino;
  269.                 if(lfinode || mklost() )
  270.                 {
  271.                 read_inode();
  272.                 cdirty=1;
  273.                 tino=cino;
  274.                 rip->i_nlinks++;
  275.  
  276.                 /* Fix link count as well */
  277.                 rip->i_nlinks-=ist->links;
  278.                 ist->links=0;
  279.  
  280.                 /* Update '..' */
  281.                 if(ist->flag & I_DD)
  282.                 {
  283.                     dir_struct dir[DPB];
  284.                     read_zone(rip->i_zone[0],dir);
  285.                     dir[incr].d_inum=lfinode;
  286.                     write_zone(rip->i_zone[0],dir);
  287.  
  288.                     if(chk_irange(ist->parent))
  289.                     {    
  290.                     inode_status[ist->parent-1].links++;
  291.                     cino=ist->parent;
  292.                     read_inode();
  293.                     cdirty=1;
  294.                     rip->i_nlinks--;
  295.                     }
  296.  
  297.                 }
  298.  
  299.                 cino=lfinode;
  300.                 sprintf(tdir[0].d_name,"%d",tino);
  301.                 tdir[0].d_inum=tino;
  302.  
  303.                 read_inode();
  304.                 if(ist->flag & I_DD) rip->i_nlinks++;
  305.                 cdirty=1;
  306.                 add_dirent(tdir);
  307.                 cino=tino;
  308.                 }
  309.             else printf("Cannot Reconnect\n");
  310.             }    
  311.         }
  312.  
  313.         if(ist->links)
  314.         {
  315.             printf("Inode %ld Bad Link Count\n",cino);
  316.             if(ask("Alter?","Altered"))
  317.             {
  318.                 read_inode();
  319.                 rip->i_nlinks-=ist->links;
  320.                 ist->links=0;
  321.                 cdirty=1;
  322.             }
  323.         }
  324.  
  325.     }
  326.  
  327.     read_inode_init();
  328.  
  329.     printf("Checking Zone Bitmap\n");
  330.     for(i=1;i<=maxzone-minzone+1;i++)
  331.     {
  332.         if(!isset(i,szbitmap))
  333.         {
  334.             zfree++;
  335.             if(isset(i,zbitmap)) berr++;
  336.         }
  337.         else if(!isset(i,zbitmap)) berr++;
  338.     }
  339.  
  340.     if(berr)
  341.     {
  342.         printf("Zone Bitmap : %ld Errors\n",berr);
  343.         if(ask("Install A New Map?","Fixed"))
  344.         {
  345.             for(i=1;i<=maxzone-minzone+1;i++)
  346.             {
  347.                 if(isset(i,szbitmap)) setbit(i,zbitmap);
  348.                 else clrbit(i,zbitmap);
  349.             }
  350.             write_blocks(2+Super->s_imap_blks,Super->s_zmap_blks,zbitmap);
  351.         }
  352.     }
  353.     else printf("Zone Bitmap OK\n");
  354.  
  355.     berr=0;
  356.     ist=inode_status;
  357.     printf("Checking Inode Bitmap\n");
  358.  
  359.     for(i=ROOT_INODE;i<=maxino;i++,ist++)
  360.     {
  361.         if( ist->flag & I_FREE)
  362.         {
  363.             ifree++;
  364.             if(isset(i,ibitmap)) berr++;
  365.         }
  366.         else if(!isset(i,ibitmap)) berr++;
  367.     }
  368.  
  369.     if(berr)
  370.     {
  371.         printf("Inode Bitmap : %ld Errors\n",berr);
  372.         if(ask("Install A New Map?","Fixed"))
  373.         {
  374.             ist=inode_status;
  375.             for(i=ROOT_INODE;i<=maxino;i++,ist++)
  376.             {
  377.                 if(ist->flag & I_FREE) clrbit(i,ibitmap);
  378.                 else setbit(i,ibitmap);
  379.             }
  380.             write_blocks(2,Super->s_imap_blks,ibitmap);
  381.         }
  382.     }
  383.     else printf("Inode Bitmap OK\n");
  384.  
  385.     read_inode_init();
  386.  
  387. }
  388.  
  389. /* traverse_zones passes pointers of the zone numbers of inode 'rip' to the 
  390.  * function argument, if the value returned is non-zero then number was altered.
  391.  * Also pass a 'level' parameter, this is zero for zone numbers, 1 for 
  392.  * indirection blocks and 2 for double indirection blocks.
  393.  */
  394.  
  395. static void traverse_zones(func)
  396. int (*func)(zone_nr *zone,unsigned level);
  397. {
  398.     zone_nr i,j;
  399.     zone_nr tmp1[NINDIR],tmp2[NINDIR];
  400.  
  401.     zonecount=(rip->i_size+BLOCKSIZE-1)/BLOCKSIZE;
  402.     indcount=NO_IND(zonecount);
  403.     dindcount=NO_DBL(zonecount);
  404.  
  405.     if(trunc!=2) trunc=0; /* 2 means silently truncate (directory) */
  406.     done_trunc=0;
  407.  
  408.     for(i=0;i<NR_ZONE;i++)
  409.         if( (*func)(&rip->i_zone[i],(i<NDIR) ? 0 : (i-NDIR+1) ) )
  410.                                        cdirty=1;
  411.  
  412.     if( chk_range(rip->i_zone[NDIR]) )
  413.     {
  414.         int zdirty=0;
  415.         read_zone(rip->i_zone[NDIR],tmp1);
  416.  
  417.         for(i=0;i<NINDIR;i++) if( (*func)(&tmp1[i],0) ) zdirty=1;
  418.         if(zdirty) write_zone(rip->i_zone[NDIR],tmp1);
  419.     }
  420.     else zonecount-=NINDIR;
  421.  
  422.     if( chk_range(rip->i_zone[NDIR+1]) )
  423.     {
  424.         int zdirty=0;
  425.         read_zone(rip->i_zone[NDIR+1],tmp1);
  426.         for(i=0;i<NINDIR;i++)
  427.         {
  428.             if( (*func)(&tmp1[i],1) )
  429.             {
  430.                 zdirty=1;
  431.                 continue;
  432.             }
  433.             if( chk_range(tmp1[i]) )
  434.             {
  435.                 int zdirty2=0;
  436.                 read_zone(tmp1[i],tmp2);
  437.                 for(j=0;j<NINDIR;j++)
  438.                     if( (*func)(&tmp2[j],0) ) zdirty2=1;
  439.                 if(zdirty2) write_zone(tmp1[i],tmp2);
  440.             }
  441.             else zonecount-=NINDIR;
  442.  
  443.             if(zdirty) write_zone(rip->i_zone[NDIR+1],tmp1);
  444.         }
  445.     }
  446. }
  447.  
  448. /* Pass 1 zone traversal , check zone range and note in bitmap, do truncation
  449.  * if too many zones.
  450.  */
  451.  
  452. static int pass1(zone,level)
  453. zone_nr *zone;
  454. unsigned level;
  455. {
  456.  
  457.     if(!done_trunc || trunc)
  458.     {
  459.         switch(level)
  460.         {
  461.             case 0:
  462.  
  463.             if(zonecount==0)
  464.             {
  465.                 if(*zone && ( trunc || do_trunc() ) )
  466.                 {
  467.                     *zone=0;
  468.                     return 1;
  469.                 }
  470.             }
  471.             else zonecount--;
  472.             break;
  473.  
  474.             case 1:
  475.             if(indcount==0)
  476.             {
  477.                 if(*zone && ( trunc || do_trunc() ) )
  478.                 {
  479.                     *zone=0;
  480.                     return 1;
  481.                 }
  482.             }
  483.             else indcount--;
  484.             break;
  485.  
  486.             case 2:
  487.             if(dindcount==0)
  488.             {
  489.                 if(*zone && (trunc || do_trunc() ) )
  490.                 {
  491.                     *zone=0;
  492.                     return 1;
  493.                 }
  494.             }
  495.             else dindcount--;
  496.             break;
  497.         }
  498.     }
  499.  
  500.     if(!*zone) return 0; /* zero is legitimate */
  501.     if( (*zone < minzone) || (*zone > maxzone) )
  502.     {
  503.         printf("Zone number out of range in inode %ld\n",cino);
  504.         if(ask("Remove?","Removed"))
  505.         {
  506.             *zone=0;
  507.             return 1;
  508.         }
  509.     }
  510.     else if(mark_zone(*zone)) add_dup(*zone);
  511.     return 0;
  512. }
  513.  
  514. /* Comment : at the end of pass 1 we have a (possibly empty) list of duplicate
  515.  * zones. The crucial point is that they are in the order of finding by 
  516.  * traverse_zones, except the first element is missing, this is tackled by
  517.  * pass1a.
  518.  */
  519.  
  520. /* Pass 1a zone traversal , find first duplicate zones and fix */
  521.  
  522. static int pass1a(zone,level)
  523. zone_nr *zone;
  524. unsigned level;
  525. {
  526.     if(!chk_range(*zone)) return 0;
  527.     if(is_dup(*zone))
  528.     {
  529.         /* Found first member of duplicate zones, prepend
  530.          * to list.
  531.          */
  532.  
  533.         zlist *new;
  534.         new=malloc(sizeof(zlist));
  535.         if(!new) fatal("No memory for duplist\n");
  536.         new->next=fzlist;
  537.         new->mod=rip->i_mtime;
  538.         new->inum=cino;
  539.         new->zone=*zone;
  540.         new->flag=0;
  541.         fzlist=new;
  542.         do_dup(*zone);
  543.     }
  544.     if(is_rem(*zone))
  545.     {
  546.         printf("Removing Zone %ld Inode %ld\n",(long)*zone,cino);
  547.         *zone=0;
  548.         return 1;
  549.     }
  550.     return 0;
  551. }
  552.  
  553. /* add_dup(zone) adds 'zone' to the duplicate list, this is put at the end
  554.  * so that the duplicate zone reflects the position of finding.
  555.  */
  556.  
  557. static void add_dup(zone)
  558. zone_nr zone;
  559. {
  560.     zlist *tlist;
  561.     tlist=(zlist *)malloc(sizeof(zlist));
  562.     if(!tlist) fatal("No memory for duplicate list");
  563.     tlist->zone=zone;
  564.     tlist->inum=cino;
  565.     tlist->mod=rip->i_mtime;
  566.     tlist->next=NULL;
  567.     tlist->flag=0;
  568.     if(lzlist)
  569.     {
  570.         lzlist->next=tlist;
  571.         lzlist=tlist;
  572.     }
  573.     else
  574.     {
  575.         fzlist=tlist;
  576.         lzlist=tlist;
  577.     }
  578. }
  579.  
  580. /* This determines what happens when duplicate zones are all found, the
  581.  * flag FOUND is set on each zone so that we now know that all the list
  582.  * of duplicates for this zone is complete. The user has the choice to
  583.  * remove each zone. Each removal is noted by the flag REMOVE, so that
  584.  * when the zones are tested by is_rem(), they are removed in order.
  585.  */
  586.  
  587. static void do_dup(zone)
  588. zone_nr zone;
  589. {
  590.     zlist *p;
  591.     printf("Zone %ld is multiply allocated\nInode list:\n",(long)zone);
  592.     for(p=fzlist;p;p=p->next)
  593.     {
  594.         if(p->zone!=zone)continue;
  595.         p->flag|=FOUND;
  596.         printf("Inode %d\n",p->inum);
  597.         printf("Mod time %s\n",ctime(&p->mod));
  598.         if(ask("Remove Zone?","Removed")) p->flag |=REMOVE;
  599.     }
  600. }
  601.  
  602. /* Return non-zero if 'zone' is a duplicate. If the FOUND flag is set for
  603.  * this zone ignore the request, as it means that this duplicate zone list
  604.  * is complete.
  605.  */
  606.  
  607. static int is_dup(zone)
  608. zone_nr zone;
  609. {
  610.     zlist *p;
  611.     for(p=fzlist;p;p=p->next)
  612.         if(p->zone==zone)
  613.         {
  614.             if(p->flag & FOUND) return 0;
  615.             return 1;
  616.         }
  617.     return 0;
  618. }
  619.  
  620. /* Returns non-zero if zone is marked for removing, if it is marked then
  621.  * remove the zone member from the duplicate list. If it isn't then set 
  622.  * the flag IGNORE so that subsequent is_rem()'s pass over it silently.
  623.  * If the zone is removed and no zones remain with this number, free its
  624.  * entry in the zone bitmap.
  625.  */
  626.  
  627. static int is_rem(zone)
  628. zone_nr zone;
  629. {
  630.     zlist *p,*q;
  631.     for(p=fzlist,q=0;p;p=p->next)
  632.     {
  633.         if( (p->zone==zone) && !(p->flag & IGNORE))
  634.         {
  635.             if(p->flag & REMOVE)
  636.             {
  637.                 if(!q) fzlist=p->next;
  638.                 else q->next=p->next;
  639.                 free(p);
  640.                 if(p==lzlist) lzlist=q;
  641.                 /* Last reference ? */
  642.                 for(p=fzlist;p && (p->zone!=zone);p=p->next) ;
  643.                 if(!p) unmark_zone(zone);
  644.                 return 1;
  645.             }
  646.             p->flag |= IGNORE;
  647.             return 0;
  648.         }
  649.         q=p;
  650.     }
  651.     return 0;
  652. }
  653.  
  654. /* check_root() test the root inode, determine directory increment if none
  655.  * specified.
  656.  */
  657.  
  658. static void check_root()
  659. {
  660.     dir_struct dir[DPB];
  661.     int i;
  662.     int oddroot;
  663.     read_inode_init();
  664.     cino=ROOT_INODE;
  665.     read_inode();
  666.     if((rip->i_mode & I_TYPE)!=I_DIRECTORY)
  667.     {
  668.         fprintf(stderr,"Root Inode Not a Directory\n");
  669.         if(!incr && ask("Check anyway?","Continuing...")) oddroot=1;
  670.         else
  671.         {
  672.           if(!incr)
  673.           {
  674.             fprintf(stderr,"Enter Increment Manually with '-d' option\n");
  675.             close_device();
  676.             exit(1);
  677.           }
  678.           if(!ask("Reallocate?","Reallocated"))
  679.           {
  680.             close_device();
  681.             exit(1);
  682.           }
  683.           badroot=1;
  684.           return;
  685.         }
  686.     }
  687.     else oddroot=0;
  688.  
  689.     if(incr) return;
  690.     if(!chk_range(rip->i_zone[0]))
  691.     {
  692.         fprintf(stderr,"Bad First Zone In Root Inode\n");
  693.         if(!ask("Assume Increment 1?","Assuming increment 1"))
  694.         {
  695.             close_device();
  696.             exit(1);
  697.         }
  698.         incr=1;
  699.         return;    
  700.     }
  701.  
  702.     read_zone(rip->i_zone[0],dir);
  703.  
  704.     if(strcmp(dir->d_name,"."))
  705.     {
  706.         fprintf(stderr,"No or bad '.' in Root Inode.\n");
  707.         fprintf(stderr,"Use the '-d' option to set increment.\n");
  708.         close_device();
  709.         exit(1);
  710.     }
  711.  
  712.     for(i=1;i<DPB;i++) if(!strcmp(dir[i].d_name,"..")) break;
  713.  
  714.     if(NPOW2(i) || (i > 8))
  715.     {
  716.         fprintf(stderr,"Can't Work Out Increment: Use the -d option\n");
  717.         close_device();
  718.         exit(1);
  719.     }
  720.  
  721.     incr=i;
  722.  
  723. #ifdef V1
  724.     /* Linux compatability */
  725.     if(incr==2 && Super->s_magic==SUPER_V1)
  726.     {
  727.         fprintf(stderr,
  728.             "Old Style Superblock for V1, increment 2 filesystem\n");
  729.         if(ask("Convert?","Converted"))
  730.         {
  731.             Super->s_magic=SUPER_V1_30;
  732.             write_zone(1,Super);
  733.         }
  734.     }
  735. #endif
  736.     if(oddroot)
  737.     {
  738.         fprintf(stderr,"Root Inode not directory but otherwise OK.\n");
  739.         if(!ask("Fix?","Fixed")) return;
  740.         rip->i_mode= I_DIRECTORY | 0777;
  741.         cdirty=1;
  742.         read_inode_init();
  743.     }
  744.  
  745.     return;
  746. }
  747.  
  748. /* traverse_dir(), send all the entries of a dir (with the entry number),
  749.  * to the function 'func'. If this returns non-zero then the entry was
  750.  * modified, BUG: Ignores double-indirection block, but anyone with a
  751.  * directory this big must be doing it to try and fool us (it means more
  752.  * than 33000 entries !).
  753.  */
  754.  
  755. static void traverse_dir(func)
  756. int (*func)();
  757. {
  758.     unsigned entry=0;
  759.     long nentries=rip->i_size/(DSIZE*incr),i;
  760.     zone_nr nzones=(nentries+DPB/incr-1)/(DPB/incr);
  761.     dir_struct dir[DPB];
  762.     zone_nr znr;
  763.     for(znr=0;znr < min(NDIR,nzones); znr++)
  764.     {
  765.         if(chk_range(rip->i_zone[znr]))
  766.         {
  767.             int zdirty=0;
  768.             read_zone(rip->i_zone[znr],dir);
  769.             for(i=0;(i<min(DPB/incr,nentries)) && !quit_trav;
  770.                                     i++,entry++)
  771.                 if((*func)(&dir[i*incr],entry)) zdirty=1;
  772.             if(zdirty) write_zone(rip->i_zone[znr],dir);
  773.             if(quit_trav) return;
  774.         }
  775.         else entry +=DPB/incr;
  776.         nentries-=DPB/incr;
  777.         if(nentries<=0) return;
  778.     }
  779.     nzones-=NDIR;
  780.     if(chk_range(rip->i_zone[NDIR]) )
  781.     {
  782.         zone_nr tmp[NINDIR];
  783.         read_zone(rip->i_zone[NDIR],tmp);
  784.         for(znr=0;znr<min(NINDIR,nzones);znr++)
  785.         {
  786.             if(chk_range(tmp[znr]))
  787.             {
  788.                 int zdirty=0;
  789.                 read_zone(tmp[znr],dir);
  790.                 for(i=0;(i<min(DPB/incr,nentries)) && !quit_trav;
  791.                                 i++,entry++)
  792.                     if( (*func)(&dir[i*incr],entry) )zdirty=1;
  793.                 if(zdirty) write_zone(tmp[znr],dir);
  794.                 if(quit_trav) return;
  795.             }
  796.             else entry +=DPB/incr;
  797.             nentries-=DPB/incr;
  798.             if(nentries<=0) return;
  799.         }
  800.     }
  801. }
  802.  
  803. /* Add an entry to a dir, this uses traverse_dir to see if there are any
  804.  * free slots, if not then add a zone.
  805.  */
  806.  
  807. static long lastentry;
  808. static dir_struct *add;
  809. static dir_struct newzone[DPB];
  810.  
  811. static int add_dirent(adir)
  812. dir_struct *adir;
  813. {
  814.     long tsize,zoneadd,addz;
  815.     tsize=rip->i_size;
  816.     /* Expand the dir by one entrylength, reset later if get empty slot */
  817.     rip->i_size+=DSIZE*incr;
  818.     rip->i_size &= ~(DSIZE*incr-1);
  819.     lastentry=rip->i_size/(DSIZE*incr)-1;
  820.     add=adir;
  821.     quit_trav=0;
  822.     traverse_dir(addfunc);
  823.     if(quit_trav)
  824.     {
  825.         /* If not last entry, restore size */
  826.         if(quit_trav==1) rip->i_size=tsize;
  827.         else cdirty=1;
  828.         quit_trav=0;
  829.         return 0;
  830.     }
  831.  
  832.     /* OK, need to add a zone, ignore any zone numbers already here,
  833.      * if there are any then they are bogus and should have been 
  834.      * removed in pass1.
  835.      */
  836.  
  837.     cdirty=1;
  838.     zoneadd=rip->i_size/BLOCKSIZE;
  839.  
  840.     if(!(addz=alloc_zone()))
  841.     {
  842.         printf("No free Zones\n");
  843.         return 1;
  844.     }
  845.     /* Room in direct zones ? */
  846.     if(zoneadd<NDIR) rip->i_zone[zoneadd]=addz;
  847.     else
  848.     /* Nope, need indirecton block */
  849.     {
  850.         zone_nr tmp[NINDIR];
  851.         zoneadd-=NDIR;
  852.         if(zoneadd >= NINDIR)
  853.         {
  854.             printf("Can't Expand Directory, Too Large\n");
  855.             clrbit(addz-minzone+1,szbitmap);
  856.             return 1;
  857.         }
  858.         if(!chk_range(rip->i_zone[NDIR]))
  859.         {
  860.             bzero((char *)tmp,BLOCKSIZE);
  861.             if( !(rip->i_zone[NDIR]=alloc_zone()) )        
  862.             {
  863.                 printf("No Free Zones\n");
  864.                 clrbit(addz-minzone+1,szbitmap);
  865.                 return 1;
  866.             }
  867.         }
  868.         else read_zone(rip->i_zone[NDIR],tmp);
  869.         tmp[zoneadd]=addz;
  870.         write_zone(rip->i_zone[NDIR],tmp);
  871.     }
  872.     cpdir(newzone,adir);
  873.  
  874.     write_zone(addz,newzone);
  875.     return 0;
  876. }
  877.  
  878. static int addfunc(dir,entry)
  879. dir_struct *dir;
  880. unsigned entry;
  881. {
  882.     if(entry<2) return 0;
  883.     /* If free , or last entry, overwrite */
  884.     if(!dir->d_inum || entry==lastentry)
  885.     {
  886.         cpdir(dir,add);
  887.         quit_trav=1;
  888.         if(entry==lastentry) quit_trav=2;
  889.         return 1;
  890.     }
  891.     return 0;
  892. }
  893.  
  894. static char *tname;
  895. static unsigned ifind;
  896.  
  897. static void show_name(inl)
  898. ilist *inl;
  899. {
  900.     inode_stat *itmp;
  901.  
  902.     char *tmpfnam;
  903.  
  904.     long pathlen;
  905.  
  906.     if(!(tname=malloc(incr*16-1)) ) fatal("Out of memory");
  907.  
  908.     /* Estimate maximum filename length of file
  909.      * do this by counting how many directories we pass
  910.      * through on way to root. Then assume all maximum
  911.      * length.
  912.      */
  913.  
  914.     for(pathlen=0,itmp=&inode_status[inl->iparent-1];;)
  915.     {
  916.         if(!(itmp->flag & I_FOUND)) break;
  917.         pathlen++;
  918.         if(itmp==inode_status) break;
  919.         itmp=&inode_status[itmp->parent-1];
  920.     }
  921.  
  922.     /* original link not counted so far and include \'s */
  923.  
  924.     pathlen = (pathlen+1)*incr*17-1;
  925.  
  926.     tmpfnam = malloc(pathlen);
  927.  
  928.     if(!tmpfnam) fatal("Out of Memory");
  929.  
  930.     strcpy(tmpfnam,inl->name);
  931.     strrev(tmpfnam);
  932.     strcat(tmpfnam,"\\");
  933.  
  934.     itmp=&inode_status[inl->iparent-1];
  935.     ifind=inl->iparent;
  936.  
  937.     while(ifind!=ROOT_INODE)
  938.     {
  939.         if(itmp->flag & I_FOUND)
  940.         {
  941.             lookup_name(itmp);
  942.             if(!*tname)
  943.             {
  944.                 fprintf(stderr,
  945.                     "Can't find name of inode %d\n",inl->inum);
  946.                 return;
  947.             }
  948.             strrev(tname);
  949.             strcat(tmpfnam,tname);
  950.             strcat(tmpfnam,"\\");
  951.         }
  952.         else
  953.         {
  954.             strcat(tmpfnam,"(nahpro)");
  955.             /* "orphan" backwards, geddit? */
  956.             break;
  957.         }        
  958.         ifind=itmp->parent;
  959.         itmp=&inode_status[itmp->parent-1];
  960.         
  961.     }
  962.  
  963.     strrev(tmpfnam);
  964.     fprintf(stderr,"Inode %5d Filename: %s\n",inl->inum,tmpfnam);
  965.  
  966.     free(tname);
  967.     free(tmpfnam);
  968. }
  969.  
  970. static void lookup_name(in)
  971. inode_stat *in;
  972. {
  973.     cino=in->parent;
  974.     tname[0]=0;
  975.     read_inode();
  976.     traverse_dir(i_to_name);
  977.     quit_trav=0;
  978. }    
  979.  
  980. static int i_to_name(dir,entry)
  981. dir_struct *dir;
  982. unsigned entry;
  983. {
  984.     if(entry < 2 ) return 0;    /* Ignore dots */
  985.     if(dir->d_inum==ifind) 
  986.     {
  987.         strncpy(tname,dir->d_name,incr*16-2);
  988.         tname[incr*16-2]=0;
  989.         quit_trav=1;
  990.     }
  991.     return 0;
  992. }
  993.  
  994. /* Make a 'lost+found' directory if none exists */
  995.  
  996. static int mklost()
  997. {
  998.     unsigned tino;
  999.     unsigned ctemp;
  1000.     zone_nr tzone;
  1001.     int i;
  1002.     dir_struct dir[DPB];
  1003.     printf("No lost+found directory\n");
  1004.     if(!ask("Create?","Created")) return 0;
  1005.     tino=alloc_inode();
  1006.     if(!tino) return 0;
  1007.     if(!(tzone=alloc_zone())) return 0;
  1008.     ctemp=cino;
  1009.     cino=tino;
  1010.     read_inode();
  1011.     for(i=1;i<NR_ZONE;i++) rip->i_zone[i]=0;
  1012.     rip->i_zone[0]=tzone;
  1013.     rip->i_mode=I_DIRECTORY | 0755;
  1014.     rip->i_mtime=time(NULL);
  1015.     rip->i_uid=0;
  1016.     rip->i_gid=0;
  1017.     rip->i_size=DSIZE*2*incr;
  1018.     rip->i_nlinks=2;
  1019.     cdirty=1;
  1020.     strcpy(dir[0].d_name,".");
  1021.     dir[0].d_inum=tino;
  1022.     strcpy(dir[incr].d_name,"..");
  1023.     dir[incr].d_inum=ROOT_INODE;
  1024.     write_zone(tzone,dir);
  1025.  
  1026.     strcpy(dir[0].d_name,lfname);
  1027.     dir[0].d_inum=tino;
  1028.  
  1029.     cino=ROOT_INODE;
  1030.     read_inode();
  1031.     rip->i_nlinks++;
  1032.     cdirty=1;
  1033.  
  1034.     add_dirent(dir);
  1035.  
  1036.     cino=ctemp;
  1037.     lfinode=tino;
  1038.  
  1039.     inode_status[tino-1].flag = I_DIR|I_D|I_DD|I_FOUND;
  1040.     inode_status[tino-1].links=0;
  1041.     inode_status[tino-1].parent=ROOT_INODE;
  1042.  
  1043.     return 1;
  1044. }
  1045.  
  1046. /* Simple enoungh this one : check '.' and '..' are present, check '.' points
  1047.  * to this directory, note the value of '..' . Make elementary fixes as well.
  1048.  */
  1049.  
  1050. static void check_dots()
  1051. {
  1052.     dir_struct dir[DPB];
  1053.     int dirty=0;
  1054.     if(chk_range(rip->i_zone[0]))
  1055.     {
  1056.         read_zone(rip->i_zone[0],dir);
  1057.         if(strcmp(dir->d_name,"."))
  1058.         {
  1059.             printf("No '.' in directory inode %ld\n",cino);
  1060.             if(ask("Fix?","Fixed"))
  1061.             {
  1062.             /* If this entry is occupied, add an identical entry
  1063.              * to the dir, because this one will be overwritten.
  1064.              */
  1065.             if(chk_irange(dir->d_inum)) add_dirent(dir);
  1066.  
  1067.             strcpy(dir[0].d_name,".");
  1068.             dir->d_inum=cino;
  1069.             dirty=1;
  1070.             ist->flag|=I_D;
  1071.             }
  1072.         }
  1073.         else ist->flag|=I_D;
  1074.  
  1075.         if(dir->d_inum!=cino)
  1076.         {
  1077.             printf("Bad '.' Entry in directory inode %ld\n",cino);
  1078.             if(ask("Fix?","Fixed"))
  1079.             {
  1080.                 dir->d_inum=cino;
  1081.                 dirty=1;
  1082.             }
  1083.         }
  1084.  
  1085.         if(strcmp(dir[incr].d_name,".."))
  1086.         {
  1087.             printf("Missing '..' in directory inode %ld",cino);
  1088.             if(ask("Fix?","Fixed"))
  1089.             {
  1090.                 if(chk_irange(dir[incr].d_inum)) 
  1091.                             add_dirent(&dir[incr]);
  1092.  
  1093.                 strcpy(dir[incr].d_name,"..");
  1094.                 dir[incr].d_inum=0;    /* Can't fix this yet */
  1095.                 ist->flag|=I_FDD;
  1096.                 ist->flag|=I_DD;
  1097.                 dirty=1;
  1098.             }
  1099.         }
  1100.         else
  1101.         {
  1102.             ist->parent=dir[incr].d_inum;
  1103.             ist->flag|=I_DD;
  1104.         }
  1105.         if(dirty) write_zone(rip->i_zone[0],dir);
  1106.     }
  1107. }
  1108.  
  1109. /* Check inode numbers against list after checking _pass2 wont kill the entry */
  1110.  
  1111. static int pass2(dir,entry)
  1112. dir_struct *dir;
  1113. unsigned entry;
  1114. {
  1115.     int ret;
  1116.     ret=_pass2(dir,entry);
  1117.  
  1118.     if(!ret)
  1119.     {
  1120.         llist *p;
  1121.         for(p=inums;p;p=p->next) if(dir->d_inum==p->member) break;
  1122.         if(p)
  1123.         {
  1124.             ilist *nxt;
  1125.             nxt=malloc(sizeof(ilist)+incr*16);
  1126.             if(!nxt) fatal("Out of memory");
  1127.             strncpy(nxt->name,dir->d_name,incr*16-2);
  1128.             nxt->name[incr*16-2]=0;
  1129.             nxt->inum=dir->d_inum;
  1130.             nxt->iparent=cino;
  1131.             nxt->next=inolist;
  1132.             inolist=nxt;
  1133.         }
  1134.     }
  1135.  
  1136.     return ret;
  1137. }
  1138.  
  1139. /* OK this is the nasty bit. At this point we know the value of '..' in a
  1140.  * directory (if present). Check all directory entries and offer fixes, also
  1141.  * mark each inode as it is 'found' and update link counts.
  1142.  */
  1143.  
  1144. static int _pass2(dir,entry)
  1145. dir_struct *dir;
  1146. unsigned entry;
  1147. {
  1148.     inode_stat *iarr;
  1149.  
  1150.     if(!dir->d_inum) return 0;
  1151.  
  1152.     if(!chk_irange(dir->d_inum))
  1153.     {
  1154.         inerr("Ilegal Inode Number\n");
  1155.         if(ask("Delete?","Deleted"))
  1156.         {
  1157.             dir->d_inum=0;
  1158.             return 1;
  1159.         }
  1160.         return 0;    /* Can't do anything else with it */
  1161.     }
  1162.  
  1163.     if( (cino==ROOT_INODE) && !strcmp(dir->d_name,lfname))lfinode=dir->d_inum;
  1164.  
  1165.     iarr=&inode_status[dir->d_inum-1];
  1166.     iarr->links--;
  1167.  
  1168.     if(badname(dir->d_name))
  1169.     {
  1170.         printf("Bad Name %.*s in Directory Inode %ld\n",
  1171.                     MMAX_FNAME(incr),dir->d_name,cino);
  1172.         if(ask("Delete?","Deleted"))
  1173.         {
  1174.             dir->d_inum=0;
  1175.             iarr->links++;
  1176.             return 1;
  1177.         }
  1178.     }
  1179.  
  1180.     if(entry && (!strcmp(dir->d_name,".")))
  1181.     {
  1182.         inerr("Extra '.' entry");
  1183.         if(ask("Delete?","Deleted"))
  1184.         {
  1185.             dir->d_inum=0;
  1186.             iarr->links++;
  1187.             return 1;
  1188.         }
  1189.         return 0;
  1190.     }
  1191.  
  1192.     if( (entry!=1) && !strcmp(dir->d_name,"..") )
  1193.     {
  1194.         inerr("Extra '..' entry");
  1195.         if(ask("Delete?","Deleted"))
  1196.         {
  1197.             dir->d_inum=0;
  1198.             iarr->links++;
  1199.             return 1;
  1200.         }
  1201.         return 0;
  1202.     }
  1203.  
  1204.     if( ( (entry==0) && (ist->flag & I_D) )
  1205.                 || ( (entry==1) && (ist->flag & I_DD ) ) )
  1206.             return 0;
  1207.  
  1208.     if(iarr->flag & I_FREE)
  1209.     {
  1210.         inerr("Bad Link To Free Inode");
  1211.         if(ask("Delete?","Deleted"))
  1212.         {
  1213.             dir->d_inum=0;
  1214.             iarr->links++;
  1215.             return 1;
  1216.         }
  1217.         return 0;
  1218.     }
  1219.  
  1220.     /* Tricky bit : link to directory. For this pass only recognise as
  1221.      * 'found' if the link is present in the correct parent directory.
  1222.      * If this isn't the case either '..' is wrong or this is an illegal
  1223.      * hard link, this is resolved on the next pass.
  1224.      * If it isn't a directory then mark found, as multiple links are OK.
  1225.      */
  1226.     if(iarr->flag & I_DIR)
  1227.     {
  1228.         if (iarr->parent==cino)
  1229.         {
  1230.     /* If the 'FOUND' flag is set then multiple links in this dir */
  1231.             if(iarr->flag & I_FOUND)
  1232.             {
  1233.                 inerr("Illegal Hard Link To Directory");
  1234.                 if(ask("Remove","Removed"))
  1235.                 {
  1236.                     dir->d_inum=0;
  1237.                     iarr->links++;
  1238.                     return 1;
  1239.                 }
  1240.             }
  1241.             else iarr->flag |= I_FOUND;
  1242.         }
  1243.         else ist->flag |= I_LINK;
  1244.     }
  1245.     else iarr->flag |= I_FOUND;
  1246.  
  1247.     return 0;
  1248. }
  1249.  
  1250. /* At this point all directories which have a link in '..' have the flag
  1251.  * I_FOUND. So if a hard link to a directory is found then it is one of:
  1252.  * 1. An erroneous hard link (if it isn't in the parent and I_FOUND set).
  1253.  * 2. A proper link but the value of '..' is wrong in the linked dir.
  1254.  * If '..' is wrong and two hard links are found then the first is taken to
  1255.  * be valid, there isn't any real way to find out the genuine link in this
  1256.  * case.
  1257.  */
  1258.  
  1259. static int pass2a(dir,entry)
  1260. dir_struct *dir;
  1261. unsigned entry;
  1262. {
  1263.     inode_stat *iarr;
  1264.     /* Ignore dot's and invalid links */
  1265.     if( (!entry && (ist->flag & I_D) )||
  1266.         (entry==1 && (ist->flag & I_DD) ) ||
  1267.         !chk_irange(dir->d_inum) ) return 0;    
  1268.     iarr=&inode_status[dir->d_inum-1];
  1269.     /* If not dir , ignore */
  1270.  
  1271.     if(! (iarr->flag & I_DIR) ) return 0;
  1272.  
  1273.     /* Is this the parent ? */
  1274.     if(iarr->parent==cino) return 0;
  1275.  
  1276.     /* Does parent have a valid link ? */
  1277.     if(iarr->flag & I_FOUND)
  1278.     {
  1279.         printf("Bad Hard Link to Directory in Inode %ld\n",cino);
  1280.         if(ask("Remove?","Removed"))
  1281.         {
  1282.             dir->d_inum=0;
  1283.             iarr->links++;
  1284.             return 1;
  1285.         }
  1286.         return 0;
  1287.     }
  1288.  
  1289.     /* Hmm '..' parent has no link, must be invalid '..' */
  1290.  
  1291.     iarr->flag|=I_FOUND;
  1292.     iarr->flag|=I_FIXDD;
  1293.     iarr->parent=cino;
  1294.     return 0;
  1295. }
  1296.  
  1297. /* Almost there: fix any directories '..' entries if there is an
  1298.  * error found, if the I_FDD flag is set, do the changes silently.
  1299.  */
  1300.  
  1301. static void fix_dots()
  1302. {
  1303.     dir_struct dir[DPB];
  1304.     if(!(ist->flag & I_FDD)) 
  1305.     {
  1306.         inerr("Bad '..' entry");
  1307.         if(!ask("Fix?","Fixed")) return;
  1308.     }
  1309.     read_zone(rip->i_zone[0],dir);
  1310.     if(chk_irange(dir[incr].d_inum))
  1311.                 inode_status[dir[incr].d_inum-1].links++;
  1312.     dir[incr].d_inum=ist->parent;
  1313.     inode_status[ist->parent-1].links--;
  1314.     write_zone(rip->i_zone[0],dir);
  1315. }
  1316.  
  1317. /* Inode readers : there are two of these. next_inode() is used in the
  1318.  * initial stages where all inodes have to be read twice, it uses a big
  1319.  * buffer for this purpose, if the 'cdirty' flag is set then it writes out
  1320.  * the buffer first.
  1321.  */
  1322.  
  1323. static d_inode *ncache_start,*ncache_end,*ncache;
  1324. static long ncache_blk;
  1325.  
  1326. /* Initialise and flush big cache */
  1327. static void next_init()
  1328. {
  1329.     if(!ncache_start)
  1330.     {
  1331.         ncache_start=malloc(NSIZE*BLOCKSIZE);
  1332.         if(!ncache_start)fatal("No memory for inode cache");
  1333.         ncache_end=ncache_start+NSIZE*IPB;
  1334.     }
  1335.     if(cdirty) write_blocks(ncache_blk,NSIZE,ncache_start);
  1336.     cdirty=0;
  1337.     ncache=ncache_start;
  1338.     ncache_blk=0;
  1339. }
  1340.  
  1341. static void next_inode()
  1342. {
  1343.     if(ncache_blk==0)
  1344.     {
  1345.         read_blocks(ioff,NSIZE,ncache_start);
  1346.         ncache_blk=ioff;
  1347.     }
  1348.     if(ncache!=ncache_end)
  1349.     {
  1350.         rip=ncache;
  1351.         ncache++;
  1352.         return;
  1353.     }
  1354.     if(cdirty)
  1355.     {
  1356.         cdirty=0;
  1357.         write_blocks(ncache_blk,NSIZE,ncache_start);
  1358.     }
  1359.     ncache_blk+=NSIZE;
  1360.     read_blocks(ncache_blk,NSIZE,ncache_start);
  1361.     ncache=ncache_start;
  1362.     rip=ncache;
  1363.     ncache++;
  1364.     return;
  1365. }
  1366.  
  1367. static d_inode ltmp[IPB];
  1368.  
  1369. static void read_inode_init()
  1370. {
  1371.     if(cdirty)
  1372.     {
  1373.         write_blocks(ncache_blk,1,ltmp);
  1374.         cdirty=0;
  1375.     }
  1376.     ncache_blk=0;
  1377. }
  1378.  
  1379. static void read_inode()
  1380. {
  1381.     zone_nr blk=ioff+(cino-1)/IPB  ;
  1382.     if(!cino || (cino>maxino) )fatal("Internal error: inode out of range");
  1383.     if(ncache_blk!=blk)
  1384.     {
  1385.         if(cdirty)
  1386.         {
  1387.             cdirty=0;
  1388.             write_blocks(ncache_blk,1,ltmp);
  1389.         }
  1390.         ncache_blk=blk;
  1391.         read_blocks(ncache_blk,1,ltmp);
  1392.     }
  1393.     rip=<mp[(cino-1)%IPB];
  1394. }
  1395.  
  1396. static long alloc_inode()
  1397. {
  1398.     long ret;
  1399.     inode_stat *istmp=inode_status;
  1400.     for(ret=0;ret<maxino;ret++,istmp++)if(istmp->flag &I_FREE) return ret+1;
  1401.     return 0;
  1402. }
  1403.  
  1404. /* Reallocate root inode. Here the root inode is set up as a dir with '.','..'
  1405.  * and 'lost+found'. The connectivity algorithm should then be able to reconnect
  1406.  * all the orphaned inodes. Note: at this point the inode structures should at
  1407.  * least be set up, and the shadow zone bitmap, so we can safely allocate new
  1408.  * zones/inodes.
  1409.  */
  1410.  
  1411. static void fix_root()
  1412. {
  1413.     long z1,z2;
  1414.     time_t now;
  1415.  
  1416.     dir_struct rdir[DPB];
  1417.  
  1418.     cino=ROOT_INODE;
  1419.     /* First things first : allocate 2 zones */
  1420.     z1=alloc_zone();
  1421.  
  1422.     z2=alloc_zone();
  1423.  
  1424.     if(!z1 || !z2) 
  1425.         fatal("No Free Zones To Reallocate Root Inode");
  1426.  
  1427.     lfinode=alloc_inode();
  1428.  
  1429.     if(!lfinode)
  1430.         fatal("No Free Inodes To Reallocate 'lost+found'");
  1431.  
  1432.     /* Setup inode status flags */
  1433.     inode_status->flag= I_DIR | I_FOUND;
  1434.     inode_status->links=3;
  1435.     inode_status[lfinode-1].flag= I_DIR;
  1436.     inode_status[lfinode-1].links=2;
  1437.  
  1438.     read_inode_init();
  1439.     read_inode();
  1440.  
  1441.     now=time((time_t *)NULL);
  1442.  
  1443.     *rip=zinode;
  1444.  
  1445.     /* Setup root inode */
  1446.     rip->i_size= DSIZE*incr*3;        /* 3 entries */
  1447.     rip->i_mode= I_DIRECTORY | 0777;    /* Dir + 777 mode */
  1448.     rip->i_zone[0]=z1;            /* 1 Zone */
  1449.     rip->i_mtime=now;
  1450.     rip->i_nlinks=3;
  1451. #ifdef V2
  1452.     rip->i_atime=now;
  1453.     rip->i_ctime=now;
  1454. #endif
  1455.  
  1456.     /* Root Directory */
  1457.     bzero(rdir,BLOCKSIZE);
  1458.             
  1459.     strcpy(rdir[0].d_name,".");
  1460.     rdir[0].d_inum=ROOT_INODE;
  1461.     strcpy(rdir[incr].d_name,"..");
  1462.     rdir[incr].d_inum=ROOT_INODE;
  1463.     strcpy(rdir[incr*2].d_name,lfname);
  1464.     rdir[incr*2].d_inum=lfinode;
  1465.  
  1466.     write_zone(z1,rdir);
  1467.     cdirty=1;
  1468.  
  1469.     cino=lfinode;
  1470.     read_inode();
  1471.  
  1472.     /* Setup 'lost+found' inode */
  1473.     
  1474.     *rip=zinode;
  1475.  
  1476.     rip->i_size=DSIZE*incr*2;
  1477.     rip->i_mode=I_DIRECTORY | 0777;
  1478.     rip->i_zone[0]=z2;
  1479.     rip->i_mtime=now;
  1480.     rip->i_nlinks=2;
  1481. #ifdef V2
  1482.     rip->i_atime=now;
  1483.     rip->i_ctime=now;
  1484. #endif
  1485.  
  1486.     /* l+f dir same as root except for '.' */
  1487.     rdir[0].d_inum=lfinode;
  1488.  
  1489.     write_zone(z2,rdir);
  1490.     cdirty=1;
  1491.  
  1492.     read_inode_init();
  1493. }
  1494.